package top.mengchaob.deploy.service;

import top.mengchaob.deploy.table.HostServerDO;
import top.mengchaob.deploy.util.ChannelEnum;
import top.mengchaob.deploy.util.SSHUtil;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

/**
 * @title：
 * @author: mengchaob
 * @date: 2021年04月28日 15:02
 * @description:
 */
public class DeployShell {
    private HostServerDO hostServerDO=null;
    private ChannelShell channelShell=null;
    private Logger logger = LoggerFactory.getLogger(DeployShell.class);
    private InputStream inputStream = null;
    private PrintWriter printWriter = null;
    private OutputStream outputStream  = null;
    private Session session = null;
    private boolean flag=false;
    public void close(){
        if(channelShell!=null){
            channelShell.disconnect();
        }
        if(session!=null){
            session.disconnect();
        }
       if(inputStream!=null){
           try {
               inputStream.close();
           } catch (IOException ioException) {
               ioException.printStackTrace();
           }
       }
       if(printWriter!=null){
           printWriter.close();
       }
       if(outputStream!=null){
           try {
               outputStream.close();
           } catch (IOException ioException) {
               ioException.printStackTrace();
           }
       }

    }
    public DeployShell(HostServerDO hostServerDO){
        this.hostServerDO=hostServerDO;
        try {
            session = SSHUtil.getSession(hostServerDO);
            session.connect();
            channelShell = (ChannelShell)session.openChannel(ChannelEnum.SHELL.getName());
            channelShell.connect();
            inputStream = channelShell.getInputStream();//从远程端到达的所有数据都能从这个流中读取到
            outputStream  = channelShell.getOutputStream();//写入该流的所有数据都将发送到远程端。
            //使用PrintWriter流的目的就是为了使用println这个方法
            //好处就是不需要每次手动给字符串加\n
            printWriter = new PrintWriter(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
            close();
        }
    }
    public void preCmd(){
        if(hostServerDO.getBeforeCmdLocal()!=null && !"".equals(hostServerDO.getBeforeCmdLocal())){
            logger.debug("开始执行本地前置命令！");
            preCmdLocal(hostServerDO.getBeforeCmdLocal());
        }else{
            logger.debug("本地前置命令为空！");
        }
        if(hostServerDO.getBeforeCmdRemote()!=null && !"".equals(hostServerDO.getBeforeCmdRemote())){
            logger.debug("开始执行远程前置命令");
            preCmdRemote(hostServerDO.getBeforeCmdRemote());
        }else {
            logger.debug("远程前置命令为空");
        }

    }
    public void afterCmd(){
        if(hostServerDO.getAfterCmdLocal()!=null && !"".equals(hostServerDO.getAfterCmdLocal())){
            logger.debug("开始执行本地后置命令！");
            afterCmdLocal(hostServerDO.getAfterCmdLocal());
        }else{
            logger.debug("本地后置命令为空！");
        }
        if(hostServerDO.getAfterCmdRemote()!=null && !"".equals(hostServerDO.getAfterCmdRemote())){
            logger.debug("开始执行远程后置命令");
            afterCmdRemote((hostServerDO.getAfterCmdRemote()));
        }else {
            logger.debug("远程后置命令为空");
        }
    }
    private void preCmdLocal(String cmd) {
        Runtime run = Runtime.getRuntime();
        Process process = null;
        InputStream in = null;
        try {
            process = run.exec(cmd);
            in = process.getInputStream();
            BufferedReader bs = new BufferedReader(new InputStreamReader(in));
            StringBuffer out = new StringBuffer();
            byte[] b = new byte[8192];
            for (int n; (n = in.read(b)) != -1;) {
                out.append(new String(b, 0, n));
            }
            logger.debug("开始执行本地前置命令执行结果输出："+out.toString());
            in.close();
            process.destroy();
        } catch (IOException e) {
            e.printStackTrace();
            if(in!=null){
                try {
                    in.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
            if(process!=null&&process.isAlive()){
                process.destroy();
            }
        }
    }
    private void preCmdRemote(String cmd){
        logger.debug("远程前置命令执行脚本："+cmd);
        printWriter.println(cmd);
        printWriter.flush();
        printCmdLog();
    }
    private void afterCmdLocal(String cmd){
        Runtime run = Runtime.getRuntime();
        Process process = null;
        InputStream in = null;
        try {
            process = run.exec(cmd);
            in = process.getInputStream();
            BufferedReader bs = new BufferedReader(new InputStreamReader(in));
            StringBuffer out = new StringBuffer();
            byte[] b = new byte[8192];
            for (int n; (n = in.read(b)) != -1;) {
                out.append(new String(b, 0, n));
            }
            logger.debug("开始执行本地后置命令执行结果输出："+out.toString());
            in.close();
            process.destroy();
        } catch (IOException e) {
            e.printStackTrace();
            if(in!=null){
                try {
                    in.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
            if(process!=null&&process.isAlive()){
                process.destroy();
            }
        }
    }
    private void printCmdLog() {
        byte[] tmp=new byte[1024];
        try{
            while(true) {
                while (inputStream.available() > 0) {
                    int i = inputStream.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    logger.debug(new String(tmp, 0, i));
                }
                if (this.channelShell.isClosed()) {
                    if (inputStream.available() > 0) {
                        continue;
                    }
                    logger.debug("exit-status: " + this.channelShell.getExitStatus());
                    break;
                }
            }
            logger.debug("日志打印结束！");
        }catch (IOException e){
            e.printStackTrace();
        }

    }
    private void afterCmdRemote(String cmd){
        logger.debug("远程后置命令执行脚本："+cmd);
        printWriter.println(cmd);
        printWriter.flush();
        printCmdLog();

    }
}
